package fr.obsmip.sedoo.shared.domain;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.user.client.rpc.IsSerializable;

import fr.sedoo.commons.client.util.StringUtil;
import fr.sedoo.commons.client.widget.editing.ValidationAlert;
import fr.sedoo.commons.shared.domain.GeographicBoundingBoxDTO;

public class SearchCriteriaDTO implements IsSerializable{

	public static final String AND = "And";
	public static final String OR = "Or";
	private static final String CRITERIA_PADDING = "_";
	private static final String CRITERIA_SEPARATOR = "@";
	private static final String ELEMENT_SEPARATOR = "!";

	private GeographicBoundingBoxDTO boundingBoxDTO = new GeographicBoundingBoxDTO();
	private List<String> keywords = new ArrayList<String>();
	private String keywordsLogicalLink=AND;
	private String startDate;
	private String endDate;
	private List<String> observatories = new ArrayList<String>();
	private String observatory ="";
	private boolean includesDatasets = false;
	private boolean includesExperimentalSites = false;
	private boolean includesObservatories = false;
	
	public boolean isEmpty() 
	{
		if (getBoundingBoxDTO().isEmpty() ==  false)
		{
			return false;
		}
		if (keywords.isEmpty() == false)
		{
			return false;
		}
		if ((observatory != null) && (observatory.length()>0))
		{
			return false;
		}
		if (isIncludesDatasets() || isIncludesExperimentalSites() || isIncludesObservatories())
		{
			return false;
		}
		return true;
	}
	public GeographicBoundingBoxDTO getBoundingBoxDTO() {
		return boundingBoxDTO;
	}
	public void setBoundingBoxDTO(GeographicBoundingBoxDTO boundingBoxDTO) {
		this.boundingBoxDTO = boundingBoxDTO;
	}
	public List<ValidationAlert> validate() 
	{
		List<ValidationAlert> result = new ArrayList<ValidationAlert>();

		if (getBoundingBoxDTO().isEmpty() == false)
		{
			result.addAll(boundingBoxDTO.validate());
		}

		return result;
	}
	public void setKeywords(List<String> keywords) {
		this.keywords = keywords;
	}

	public List<String> getKeywords() {
		return keywords;
	}

	public String getKeywordsLogicalLink() {
		return keywordsLogicalLink;
	}
	public void setKeywordsLogicalLink(String keywordsLogicalLink) {
		this.keywordsLogicalLink = keywordsLogicalLink;
	}

	public String toToken()
	{
		StringBuffer token = new StringBuffer();

		//Critère Keywords
		Iterator<String> iterator = keywords.iterator();
		if (!keywords.isEmpty())
		{
			while (iterator.hasNext()) 
			{
				String aux = iterator.next().trim();
				if (aux.length()>0)
				{
					token.append(aux);
					if (iterator.hasNext())
					{
						token.append(ELEMENT_SEPARATOR);
					}
				}
			}
		}
		else
		{
			token.append(CRITERIA_PADDING);
		}
		token.append(CRITERIA_SEPARATOR);


		//Critère Lien logique
		token.append(getKeywordsLogicalLink());
		token.append(CRITERIA_SEPARATOR);
		//Critère GeographicBoundingBox
		if (getBoundingBoxDTO().isEmpty()== false)
		{
			token.append(getBoundingBoxDTO().getNorthBoundLatitude());
			token.append(ELEMENT_SEPARATOR);
			token.append(getBoundingBoxDTO().getEastBoundLongitude());
			token.append(ELEMENT_SEPARATOR);
			token.append(getBoundingBoxDTO().getSouthBoundLatitude());
			token.append(ELEMENT_SEPARATOR);
			token.append(getBoundingBoxDTO().getWestBoundLongitude());
			token.append(ELEMENT_SEPARATOR);
		}
		else
		{
			token.append(CRITERIA_PADDING);
		}
		token.append(CRITERIA_SEPARATOR);
		token.append(isIncludesObservatories());
		token.append(ELEMENT_SEPARATOR);
		token.append(isIncludesExperimentalSites());
		token.append(ELEMENT_SEPARATOR);
		token.append(isIncludesDatasets());
		token.append(ELEMENT_SEPARATOR);
		token.append(CRITERIA_SEPARATOR);
		String tmp = getObservatory();
		if (StringUtil.isEmpty(tmp))
		{
			token.append(CRITERIA_PADDING);
		}
		else
		{
			token.append(tmp);
		}

		return token.toString();
	}

	public static SearchCriteriaDTO fromToken(String token)
	{
		SearchCriteriaDTO result = new SearchCriteriaDTO();
		if (token.indexOf(CRITERIA_SEPARATOR)>0)
		{
			String[] split = token.split(CRITERIA_SEPARATOR);
			String keywords = split[0].trim();
			if (keywords.compareTo(CRITERIA_PADDING) != 0)
			{
				List<String> newValue = new ArrayList<String>();
				String[] aux = keywords.split(ELEMENT_SEPARATOR);
				for (int i = 0; i < aux.length; i++) 
				{
					newValue.add(aux[i]);
				}
				result.setKeywords(newValue);
			}

			String logicalLink = split[1].trim();
			result.setKeywordsLogicalLink(logicalLink);

			String boundingBox = split[2].trim();
			if (boundingBox.compareTo(CRITERIA_PADDING) != 0)
			{
				String[] aux = boundingBox.split(ELEMENT_SEPARATOR);
				GeographicBoundingBoxDTO boundingBoxDTO = result.getBoundingBoxDTO();
				boundingBoxDTO.setNorthBoundLatitude(aux[0]);
				boundingBoxDTO.setEastBoundLongitude(aux[1]);
				boundingBoxDTO.setSouthBoundLatitude(aux[2]);
				boundingBoxDTO.setWestBoundLongitude(aux[3]);
			}
			String entryTypes = split[3].trim();
			if (entryTypes.compareTo(CRITERIA_PADDING) != 0)
			{
				String[] aux = entryTypes.split(ELEMENT_SEPARATOR);
				result.setIncludesObservatories(new Boolean(aux[0]));
				result.setIncludesExperimentalSites(new Boolean(aux[1]));
				result.setIncludesDatasets(new Boolean(aux[2]));
			}
			String observatory = split[4].trim();
			if (observatory.compareTo(CRITERIA_PADDING) != 0)
			{
				result.setObservatory(observatory);
			}
		}
		return result;
	}
	public String getStartDate() {
		return startDate;
	}
	public void setStartDate(String startDate) {
		this.startDate = startDate;
	}
	public String getEndDate() {
		return endDate;
	}
	public void setEndDate(String endDate) {
		this.endDate = endDate;
	}
	public List<String> getObservatories() {
		return observatories;
	}
	public void setObservatories(List<String> observatories) {
		this.observatories = observatories;
	}
	public String getObservatory() {
		return observatory;
	}
	public void setObservatory(String observatory) {
		this.observatory = observatory;
	}
	public boolean isIncludesDatasets() {
		return includesDatasets;
	}
	public void setIncludesDatasets(boolean includesDatasets) {
		this.includesDatasets = includesDatasets;
	}
	public boolean isIncludesExperimentalSites() {
		return includesExperimentalSites;
	}
	public void setIncludesExperimentalSites(boolean includesExperimentalSites) {
		this.includesExperimentalSites = includesExperimentalSites;
	}
	public boolean isIncludesObservatories() {
		return includesObservatories;
	}
	public void setIncludesObservatories(boolean includesObservatories) {
		this.includesObservatories = includesObservatories;
	}


}
